package com.campus.counseling.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campus.counseling.entity.PsychologicalTest;
import com.campus.counseling.entity.TestQuestion;
import com.campus.counseling.model.excel.QuestionImportModel;
import com.campus.counseling.model.mapper.TestQuestionMapper;
import com.campus.counseling.service.PsychologicalTestService;
import com.campus.counseling.model.dto.TestQuestionDTO;
import com.campus.counseling.model.query.TestQuestionQuery;
import com.campus.counseling.model.vo.TestQuestionVO;
import com.campus.counseling.service.TestQuestionService;
import com.campus.counseling.model.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class TestQuestionServiceImpl extends ServiceImpl<TestQuestionMapper, TestQuestion> implements TestQuestionService {

    private final PsychologicalTestService psychologicalTestService;
    private final ObjectMapper objectMapper;

    @Override
    public Page<TestQuestionVO> list(TestQuestionQuery query) {
        LambdaQueryWrapper<TestQuestion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(query.getTestId() != null, TestQuestion::getTestId, query.getTestId())
                .eq(query.getQuestionType() != null, TestQuestion::getQuestionType, query.getQuestionType())
                .eq(StringUtils.hasText(query.getDimension()), TestQuestion::getDimension, query.getDimension())
                .like(StringUtils.hasText(query.getQuestionText()), TestQuestion::getQuestionText, query.getQuestionText())
                .groupBy(TestQuestion::getId)
                .orderByAsc(TestQuestion::getSortNum);

        // 使用 select 方法明确指定要查询的字段
        wrapper.select(TestQuestion::getId, TestQuestion::getTestId, TestQuestion::getDimension,
                TestQuestion::getQuestionType, TestQuestion::getQuestionText, TestQuestion::getOptions,
                TestQuestion::getScore, TestQuestion::getSortNum, TestQuestion::getCreateTime,
                TestQuestion::getUpdateTime, TestQuestion::getOptionScores);

        Page<TestQuestion> page = page(new Page<>(query.getPageNum(), query.getPageSize()), wrapper);
        
        // 转换为VO对象
        Page<TestQuestionVO> voPage = new Page<>();
        BeanUtils.copyProperties(page, voPage, "records");
        
        List<TestQuestionVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createQuestion(TestQuestionDTO questionDTO) {
        TestQuestion question = new TestQuestion();
        BeanUtils.copyProperties(questionDTO, question);
        save(question);
        return question.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateQuestion(Long id, TestQuestionDTO questionDTO) {
        TestQuestion question = getById(id);
        if (question == null) {
            return false;
        }
        BeanUtils.copyProperties(questionDTO, question);
        question.setId(id);
        return updateById(question);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteQuestion(Long id) {
        return removeById(id);
    }

    @Override
    public TestQuestionVO getQuestionById(Long id) {
        TestQuestion question = getById(id);
        if (question == null) {
            return null;
        }
        return convertToVO(question);
    }

    @Override
    public List<TestQuestionVO> getQuestionsByTestId(Long testId) {
        LambdaQueryWrapper<TestQuestion> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TestQuestion::getTestId, testId)
                   .orderByAsc(TestQuestion::getSortNum);
        
        return list(queryWrapper).stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TestQuestionVO> getQuestionsByDimension(Long testId, String dimension) {
        LambdaQueryWrapper<TestQuestion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TestQuestion::getTestId, testId)
               .eq(dimension != null, TestQuestion::getDimension, dimension)
               .orderByAsc(TestQuestion::getSortNum);
        
        return list(wrapper).stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public TestQuestionVO getQuestion(Long id) {
        TestQuestion question = getById(id);
        if (question == null) {
            throw new BusinessException("题目不存在");
        }
        return convertToVO(question);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(TestQuestionDTO dto) {
        log.info("Received DTO: {}", dto);
        TestQuestion question = new TestQuestion();
        question.setTestId(dto.getTestId());
        question.setQuestionType(dto.getQuestionType());
        question.setQuestionText(dto.getQuestionText());
        question.setDimension(dto.getDimension());
        question.setScore(BigDecimal.valueOf(dto.getScore()));
        question.setSortNum(dto.getSortNum());
        
        if (dto.getQuestionType() == 3 && dto.getOptions() != null) {
            try {
                question.setOptions(objectMapper.writeValueAsString(dto.getOptions()));
                question.setOptionScores(objectMapper.writeValueAsString(dto.getOptionScores()));
                log.info("After JSON conversion - options: {}, optionScores: {}", 
                    question.getOptions(), question.getOptionScores());
            } catch (JsonProcessingException e) {
                log.error("序列化选项或分值失败", e);
                throw new BusinessException("选项格式错误");
            }
        }
        
        log.info("Final question before saving: {}", question);
        save(question);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, TestQuestionDTO dto) {
        TestQuestion question = getById(id);
        if (question == null) {
            throw new BusinessException("题目不存在");
        }
        BeanUtils.copyProperties(dto, question);
        
        if (dto.getQuestionType() == 3 && dto.getOptions() != null) {
            try {
                question.setOptions(objectMapper.writeValueAsString(dto.getOptions()));
                question.setOptionScores(objectMapper.writeValueAsString(dto.getOptionScores()));
            } catch (JsonProcessingException e) {
                log.error("序列化选项或分值失败", e);
                throw new BusinessException("选项格式错误");
            }
        }
        
        log.info("Updating question: {}", question);
        updateById(question);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchCreateQuestions(List<TestQuestionDTO> questions) {
        List<TestQuestion> entityList = questions.stream()
                .map(dto -> {
                    TestQuestion question = new TestQuestion();
                    BeanUtils.copyProperties(dto, question);
                    return question;
                })
                .collect(Collectors.toList());
        return saveBatch(entityList);
    }

    @Override
    public Map<String, Integer> getDimensionQuestionCount(Long testId) {
        LambdaQueryWrapper<TestQuestion> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TestQuestion::getTestId, testId)
                   .groupBy(TestQuestion::getDimension)
                   .select(TestQuestion::getDimension);

        // 使用SQL查询直接获取统计结果
        List<Map<String, Object>> statistics = baseMapper.selectMaps(queryWrapper);
        
        return statistics.stream()
                .filter(map -> map.get("dimension") != null)
                .collect(Collectors.toMap(
                    map -> (String) map.get("dimension"),
                    map -> ((Long) map.get("count")).intValue()
                ));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteQuestions(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        return removeByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importQuestions(MultipartFile file, Long testId) throws Exception {
        if (file == null || file.isEmpty()) {
            throw new BusinessException("请选择要导入的Excel文件");
        }

        if (testId == null) {
            throw new BusinessException("请选择所属测试");
        }

        // 验证测试是否存在
        PsychologicalTest test = psychologicalTestService.getById(testId);
        if (test == null) {
            throw new BusinessException("所选测试不存在");
        }

        // 获取测试的维度列表并添加详细日志
        List<Map<String, Object>> dimensions = psychologicalTestService.getTestDimensions(testId);
        log.info("获取到的维度列表: {}", dimensions);

        Map<String, String> dimensionNameToKeyMap;
        if (dimensions == null || dimensions.isEmpty()) {
            log.info("测试ID {} 未找到维度配置，将直接使用Excel中的维度名称", testId);
            dimensionNameToKeyMap = new HashMap<>();
        } else {
            try {
                dimensionNameToKeyMap = dimensions.stream()
                    .filter(dim -> dim.get("dimensionName") != null && dim.get("dimensionKey") != null)
                    .collect(Collectors.toMap(
                        dim -> String.valueOf(dim.get("dimensionName")),
                        dim -> String.valueOf(dim.get("dimensionKey")),
                        (v1, v2) -> v1
                    ));
                log.info("维度映射关系: {}", dimensionNameToKeyMap);
            } catch (Exception e) {
                log.error("维度映射转换失败", e);
                dimensionNameToKeyMap = new HashMap<>();
            }
        }

        Map<String, String> finalDimensionNameToKeyMap = dimensionNameToKeyMap;
        EasyExcel.read(file.getInputStream(), QuestionImportModel.class, new AnalysisEventListener<QuestionImportModel>() {
            private int rowIndex = 0;
            private final List<TestQuestion> questionList = new ArrayList<>();
            private static final int MAX_ROWS = 1000;

            @Override
            public void invoke(QuestionImportModel model, AnalysisContext context) {
                rowIndex++;
                if (rowIndex > MAX_ROWS) {
                    throw new BusinessException("单次导入不能超过" + MAX_ROWS + "条数据");
                }

                log.info("正在处理第{}行数据: {}", rowIndex, model);

                // 校验数据
                validateQuestionData(model, rowIndex, finalDimensionNameToKeyMap);

                try {
                    TestQuestion question = convertToTestQuestion(model, testId, rowIndex, finalDimensionNameToKeyMap);
                    log.info("第{}行数据转换结果: {}", rowIndex, question);
                    questionList.add(question);
                } catch (JsonProcessingException e) {
                    throw new BusinessException(String.format("第%d行数据转换失败：%s", rowIndex, e.getMessage()));
                }
            }

            private void validateQuestionData(QuestionImportModel model, int rowIndex, Map<String, String> dimensionNameToKeyMap) {
                List<String> errors = new ArrayList<>();
                
                if (!StringUtils.hasText(model.getQuestionType())) {
                    errors.add(String.format("第%d行：题目类型不能为空", rowIndex));
                }
                if (!StringUtils.hasText(model.getQuestionText())) {
                    errors.add(String.format("第%d行：题目内容不能为空", rowIndex));
                }
                if (!StringUtils.hasText(model.getDimension())) {
                    errors.add(String.format("第%d行：维度不能为空", rowIndex));
                }
                if (!StringUtils.hasText(model.getScore())) {
                    errors.add(String.format("第%d行：分值不能为空", rowIndex));
                }
                if (!StringUtils.hasText(model.getSortNum())) {
                    errors.add(String.format("第%d行：排序号不能为空", rowIndex));
                }

                // 对于量表题，验证选项和分值
                if ("量表题".equals(model.getQuestionType()) || "SCALE".equals(model.getQuestionType())) {
                    if (!StringUtils.hasText(model.getOptions())) {
                        errors.add(String.format("第%d行：量表题的选项不能为空", rowIndex));
                    }
                    if (!StringUtils.hasText(model.getOptionScores())) {
                        errors.add(String.format("第%d行：量表题的选项分值不能为空", rowIndex));
                    }
                    
                    // 验证选项和分值的数量是否匹配
                    if (StringUtils.hasText(model.getOptions()) && StringUtils.hasText(model.getOptionScores())) {
                        String[] options = model.getOptions().split(",");
                        String[] scores = model.getOptionScores().split(",");
                        if (options.length != scores.length) {
                            errors.add(String.format("第%d行：选项数量(%d)与分值数量(%d)不匹配", 
                                rowIndex, options.length, scores.length));
                        }
                    }
                }

                if (!errors.isEmpty()) {
                    throw new BusinessException(String.join("\n", errors));
                }
            }

            private TestQuestion convertToTestQuestion(QuestionImportModel model, Long testId, int rowIndex, Map<String, String> dimensionNameToKeyMap) throws JsonProcessingException {
                try {
                    TestQuestion question = new TestQuestion();
                    question.setTestId(testId);
                    question.setQuestionText(model.getQuestionText().trim());
                    
                    Integer questionType = parseQuestionType(model.getQuestionType());
                    if (questionType == null) {
                        throw new BusinessException(String.format("第%d行：无效的题目类型 '%s'", rowIndex, model.getQuestionType()));
                    }
                    question.setQuestionType(questionType);
                    
                    // 处理维度映射
                    String dimensionName = model.getDimension().trim();
                    String dimensionValue;
                    if (dimensionNameToKeyMap.isEmpty()) {
                        log.info("使用原始维度名称: {}", dimensionName);
                        dimensionValue = dimensionName;
                    } else {
                        dimensionValue = dimensionNameToKeyMap.get(dimensionName);
                        if (dimensionValue == null) {
                            log.warn("维度名称 '{}' 未找到对应的映射，使用原始名称", dimensionName);
                            dimensionValue = dimensionName;
                        } else {
                            log.info("维度 '{}' 映射为 '{}'", dimensionName, dimensionValue);
                        }
                    }
                    question.setDimension(dimensionValue);
                    
                    try {
                        question.setScore(new BigDecimal(model.getScore().trim()));
                    } catch (NumberFormatException e) {
                        throw new BusinessException(String.format("第%d行：分值格式不正确 '%s'", rowIndex, model.getScore()));
                    }
                    
                    try {
                        question.setSortNum(Integer.parseInt(model.getSortNum().trim()));
                    } catch (NumberFormatException e) {
                        throw new BusinessException(String.format("第%d行：排序号格式不正确 '%s'", rowIndex, model.getSortNum()));
                    }

                    // 处理选项
                    if (StringUtils.hasText(model.getOptions())) {
                        List<String> options = Arrays.stream(model.getOptions().split(","))
                            .map(String::trim)
                            .filter(StringUtils::hasText)
                            .collect(Collectors.toList());
                        
                        if (options.isEmpty()) {
                            throw new BusinessException(String.format("第%d行：选项格式不正确", rowIndex));
                        }
                        
                        question.setOptions(objectMapper.writeValueAsString(options));
                        
                        // 处理选项分值
                        if (StringUtils.hasText(model.getOptionScores())) {
                            String[] scores = model.getOptionScores().split(",");
                            Map<String, BigDecimal> optionScores = new HashMap<>();
                            
                            for (int i = 0; i < scores.length; i++) {
                                try {
                                    optionScores.put(String.valueOf(i + 1), new BigDecimal(scores[i].trim()));
                                } catch (NumberFormatException e) {
                                    throw new BusinessException(String.format("第%d行：选项分值'%s'格式不正确", 
                                        rowIndex, scores[i]));
                                }
                            }
                            
                            question.setOptionScores(objectMapper.writeValueAsString(optionScores));
                        }
                    }

                    return question;
                } catch (BusinessException e) {
                    throw e;
                } catch (Exception e) {
                    log.error("转换题目数据失败", e);
                    throw new BusinessException(String.format("第%d行：数据转换失败 - %s", rowIndex, e.getMessage()));
                }
            }

            private Integer parseQuestionType(String typeStr) {
                if (StringUtils.isEmpty(typeStr)) {
                    return null;
                }
                
                switch (typeStr.trim().toUpperCase()) {
                    case "单选题":
                    case "SINGLE_CHOICE":
                        return 1;
                    case "判断题":
                    case "TRUE_FALSE":
                        return 2;
                    case "量表题":
                    case "SCALE":
                        return 3;
                    default:
                        return null;
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                if (questionList.isEmpty()) {
                    throw new BusinessException("Excel文件中没有有效的题目数据");
                }

                try {
                    saveBatch(questionList);
                    log.info("成功导入{}条题目数据", questionList.size());
                } catch (Exception e) {
                    log.error("批量保存题目失败, testId: {}, error: {}", testId, e.getMessage(), e);
                    throw new BusinessException("批量保存题目失败：" + e.getMessage());
                }
            }
        }).sheet().doRead();
    }

    private TestQuestionVO convertToVO(TestQuestion question) {
        if (question == null) {
            return null;
        }
        TestQuestionVO vo = new TestQuestionVO();
        BeanUtils.copyProperties(question, vo, "options", "optionScores"); // 排除options和optionScores字段的复制
        
        // 处理选项字段
        if (question.getOptions() != null) {
            try {
                // 将JSON字符串转换为List<String>
                List<String> optionsList = com.alibaba.fastjson.JSON.parseArray(question.getOptions(), String.class);
                vo.setOptions(optionsList);
            } catch (Exception e) {
                log.error("处理题目选项失败: {}", question.getOptions(), e);
                vo.setOptions(null);
            }
        }
        
        // 处理选项分值字段
        if (question.getOptionScores() != null) {
            try {
                // 将JSON字符串转换为Map对象，使用BigDecimal类型
                Map<String, BigDecimal> optionScoresMap = com.alibaba.fastjson.JSON.parseObject(
                    question.getOptionScores(), 
                    new com.alibaba.fastjson.TypeReference<Map<String, BigDecimal>>(){}
                );
                vo.setOptionScores(optionScoresMap);
            } catch (Exception e) {
                log.error("处理选项分值失败: {}", question.getOptionScores(), e);
                vo.setOptionScores(null);
            }
        }
        
        // 获取测试名称
        if (question.getTestId() != null) {
            try {
                vo.setTestName(psychologicalTestService.getById(question.getTestId()).getTitle());
            } catch (Exception e) {
                log.error("获取测试名称失败", e);
                vo.setTestName("未知测试");
            }
        }
        
        return vo;
    }
}
